<?php

namespace App\App\Services;

use App\Models\Enroll\Enroll;
use App\Models\VoteCandidate\VoteCandidate;
use App\Morefun\Publishing\Publisher;
use Exception;
use App\Models\VoteCandidate\VoteCandidateRepository as VoteItem;
use App\Models\VoteGroup\VoteGroupRepository as VoteGroup;
use App\Models\Activity\ActivityRepository as Activity;
use App\Contracts\Services\Storage\StorageService as StorageServiceContract;
use Illuminate\Container\Container;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Arr;
use App\Models\Resource\Resource;

class VoteService
{
    /**
     * @var \Redis
     */
    protected $redis;
    protected $group;
    protected $item;
    protected $activity;
    protected $storageService;


    public function __construct(VoteGroup $group, VoteItem $item, Activity $activity, StorageServiceContract $storageService)
    {
        $this->redis = Container::getInstance()->make('redis');
        $this->group = $group;
        $this->item = $item;
        $this->activity = $activity;
        $this->storageService = $storageService;
    }

    public function getVoteCache($id)
    {
        return $this->redis->get('vote:'.$id);
    }

    public function bootstraped($id)
    {
        return $this->redis->exists('vote:'.$id) && $this->redis->exists('ranking:'.$id);
        //return $this->redis->exists('rule:'.$id) && $this->redis->exists('ranking:'.$id);
    }

    public function bootstrap($id)
    {
        try {
            $activity = $this->activity->findOne($id, [
                'name',
                'startTime',
                'endTime',
                'ruleDescription',
                'description',
                'backgroundImg',
                'isPause',
                'limit',
                'shares',
                'app_url',
                'listBackgroundImg',
                'publishing_ways',
            ]);
            $_items = $this->item->getByActivity($id, [
                'id',
                'group_id',
                'type',
                'title AS name',
                'content',
                'cover_url AS cover',
                'resource_url AS src',
                'resource_id',
                'from',
                'code',
            ]);

            $items = collect();
            foreach ($_items as $item) {
                $item->cover = $this->storageService->toHttpUrl($item->cover);
                if($item->from == Enroll::FROM_ENROLLS_JSON){
                    $content = \GuzzleHttp\json_decode($item->content, true);
                    if( Arr::exists($content, 'text')){
                        Arr::forget($content['text'], '姓名');
                        Arr::forget($content['text'], '电话');
                    }
                    $item->content = \GuzzleHttp\json_encode($content);
                }
                if (in_array($item->type, [VoteCandidate::TYPE_VIDEO, VoteCandidate::TYPE_AUDIO])) {
                    $src = Resource::query()
                        ->where('resource_id', $item->resource_id)
                        ->orderBy('id', 'DESC')
                        ->value('resource_url');

                    if (!$src) {
                        continue;
                    }

                    $item->src = $src;
                }

                $items->push($item);
            }

            $categories = $this->group->getMaps($id);

            if (!$categories) {
                //$categories = ['0' => '默认分组'];
                $categories = [];
                $groupedItems = $items->toArray();
            } else {
                $groupedItems = $items->groupBy('group_id')->toArray();
            }

            $startAt = date('Y-m-d H:i', strtotime($activity->startTime));
            $endAt = date('m-d H:i', strtotime($activity->endTime));
            $end_time = date('Y-m-d H:i', strtotime($activity->endTime));
            $shares = \GuzzleHttp\json_decode($activity->getAttribute('shares'), true);
            $thumb = Arr::get($shares, 'icon', '');
            if(empty($thumb)){
                $thumb = Arr::get($shares, 'thumb', '');
            }
            $thumb = $this->storageService->toHttpUrl($thumb);
            $limit = json_decode($activity->limit);
            $vote = [
                'title' => $activity->name,
                'name' => $activity->name,
                'type' => $activity->type,
                'duration' => $startAt . ' ~ ' . $endAt,
                'rules' => $activity->description,
                'categories' => $categories,
                'background_img' => $this->storageService->toHttpUrl($activity->backgroundImg),
                'app_url' => $activity->app_url,
                'publishing' => (new Publisher)->formatJsonString($activity->publishing_ways),
                'max_votes' => isset($limit->votes) ? $limit->votes : -1,
                'start_time' => $startAt,
                'end_time' => $end_time,
                'shares' => [
                    'isopen' => Arr::get($shares, 'isopen', 'off'),
                    'title' => Arr::get($shares, 'title', ''),
                    'content' => Arr::get($shares, 'content', ''),
                    'thumb' => $thumb,
                    'icon' => $thumb,
                ],
                'items' => $groupedItems,
            ];

            $items = $items->toArray();

            $ranks = $this->redis->zrevrangebyscore('ranking:'.$id, '+inf', 0, 'WITHSCORES');

            $this->redis->pipeline(function ($pipe) use ($id, $vote, $items, $activity, $ranks) {
                $limit = json_decode($activity->limit);
                $allow = $limit->num;
                $mode = $limit->type == 'day' ? 1 : 2;
                $maxVote = isset($limit->votes) ? $limit->votes : 0;
                $start = strtotime($activity->startTime);
                $end = strtotime($activity->endTime);

                $pipe->hmset(
                    'rule:'.$id,
                    'allow_votes',
                    $allow,
                    'brush_mode',
                    $mode,
                    'start',
                    $start,
                    'end',
                    $end,
                    'is_pause',
                    $activity->isPause,
                    'max_votes',
                    $maxVote
                );

                $voteKey = 'vote:'.$id;
                $rankingKey = 'ranking:'.$id;
                // $searchKey = 'search:'.$id;
                // $searchMaps = [];

                foreach ($items as $item) {
                    $pipe->set(
                        'item:' . $id . ":" . $item['id'],
                        json_encode(array_merge($item, ['vote_id' => $id]))
                    );

                    //防止暂停后票数被覆盖，故不种这个缓存
                    if (!array_key_exists($item['id'], $ranks)) {
                        $pipe->zadd($rankingKey, 0, $item['id']);
                    }

                    // $searchMaps[md5($item['name'])][] = $item['id'];
                }

                /*
                foreach ($searchMaps as $named => $ids) {
                    $pipe->hset($searchKey, $named, implode('||', $ids));
                }
                */
                // bootstrap success flag
                $pipe->set($voteKey, \GuzzleHttp\json_encode($vote));
            });

            return true;
        } catch (Exception $e) {
            Log::error('bootstrap redis schema failed:' . $e->getMessage());
            return false;
        }
    }

    public function registerUid($uid)
    {
        return $this->redis->hset('app:uid', $uid, 1);
    }
}
